import 'code_info.dart';

class LeakNode {
  bool isRoot = false;

  LeakNode? next;

  String? id;

  String? name;

  NodeType? type;

  String? nodeType;

  String? parentField;

  CodeInfo? codeInfo;

  String getParent() {
    String? parent;
    if (parentField != null && parentField!.contains('@')) {
      parent = parentField!.split('@')[0];
    } else {
      parent = parentField;
    }
    return parent ?? "";
  }

  @override
  String toString() {
    String? parent;
    if (parentField != null && parentField!.contains('@')) {
      parent = parentField!.split('@')[0];
    } else {
      parent = parentField;
    }
    String empty = '';
    return '[${_formatAlign('${nodeType == NodeType.FIELD.toString() ? '${codeInfo?.uri}; ${isRoot ? ' GC Root' : ""} Field -> $name' : 'name : $name'}${codeInfo == null ? '' : '  >>>  ${codeInfo?.toString()}  <<<'}', nodeType == NodeType.FIELD.toString() ? 200 : 50)} ] ${next == null ? ' ' : '${_formatAlign(parent == null ? empty : ' field -> $parent', 30)}    ↓    '
        '\n${next?.toString()}'}';
  }

  // @override
  // bool operator ==(other) {
  //   if (other is! LeakNode) {
  //     return false;
  //   }
  //   final currentNodeList = toList(this);
  //   final otherNodeList = toList(other);
  //   if (currentNodeList.length != otherNodeList.length) return false;
  //   for (int i = 0; i < currentNodeList.length; i++) {
  //     if (currentNodeList[i].nodeType != otherNodeList[i].nodeType) return false;
  //     if (currentNodeList[i].name != otherNodeList[i].name) return false;
  //     // if(currentNodeList[i].parentField != otherNodeList[i].parentField) return false;
  //     if (currentNodeList[i].codeInfo?.toJson() != otherNodeList[i].codeInfo?.toJson()) {
  //       return false;
  //     }
  //   }
  //   return true;
  // }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    data['isRoot'] = isRoot;
    data['next'] = next?.toJson();
    data['id'] = id;
    data['name'] = name;
    data['nodeType'] = nodeType;
    data['parentField'] = parentField;
    data['codeInfo'] = codeInfo?.toJson();
    return data;
  }

  LeakNode();

  LeakNode.fromJson(Map<String, dynamic> json) {
    isRoot = json['isRoot'];
    next = json['next'] != null ? LeakNode.fromJson(json['next']) : null;
    id = json['id'];
    name = json['name'];
    nodeType = json['nodeType'];
    parentField = json['parentField'];
    codeInfo = json['codeInfo'] != null ? CodeInfo.fromJson(json['codeInfo']) : null;
  }

  @override
  int get hashCode => next.hashCode ^ name.hashCode ^ nodeType.hashCode ^ codeInfo.hashCode;
}

List<LeakNode> toList(LeakNode? leakNode) {
  List<LeakNode> list = [];
  LeakNode? current = leakNode;
  while (current != null) {
    list.add(current);
    current = current.next;
  }
  return list;
}

enum NodeType { CLASS, CONTEXT, CODE, FIELD, ERROR, FUNC, INSTANCE, SCRIPT, ARGS, UN_KNOW }

String _formatAlign(String name, int len) {
  StringBuffer sb = StringBuffer();

  if (name.length > len) {
    name = name.substring(0, len);
  }
  sb.write(name);
  int fixLen = len - name.length;
  for (var i = 0; i < fixLen; i++) {
    sb.write(' ');
  }
  return sb.toString();
}
